(function($){
	
	var KEY = "jforest.flowsheet";
	
	function FlowsheetEvent(name,object,event,options){
		this.name = name;
		this.object = object;
		this.event = event;
		this.options = options;
	}
	/*
		{
			id:'',
			name:'',
			x:0,
			y:0,
			width:0,
			height:0
		}
	*/
	function FlowsheetRect(entity,options){
		this.options = $.extend({},options);
		//创建SVG元素
		this.g = entity._svg.group({transform:'translate('+this.options.x+','+this.options.y+')'});
		this.rect = entity._svg.rect(this.g,0,0,this.options.width,this.options.height,5,5,{fill:"transparent",stroke:"black",'stroke-width':3});
		this.point1 = this._createPoint(entity,options.id,1,0,this.options.height/2);  //左中
		this.point2 = this._createPoint(entity,options.id,2,this.options.width,this.options.height/2); //右中
		this.point3 = this._createPoint(entity,options.id,3,this.options.width/2,0); //上中
		this.point4 = this._createPoint(entity,options.id,4,this.options.width/2,this.options.height); //下中
		this.text = entity._svg.text(this.g,10,20,this.options.name,{fill:"red","font-size":'12px'});

		var self = this;
		//鼠标按下事件
		$(this.g).mousedown(function(event){
			entity._event = new FlowsheetEvent('move',self,event,{});
			entity._event.dx = self.options.x - event.clientX;
			entity._event.dy = self.options.y - event.clientY;
		})
		//鼠标移入事件
		$(this.g).mouseenter(function(event){
			$(self.g).attr('class','active');
		});
		//鼠标移出事件
		$(this.g).mouseleave(function(event){
			$(self.g).attr('class','');
		});
		$(this.g).dblclick(function(event){
			entity.options.dblclick.apply(self,[event]);
		});
	}
	
	$.extend(FlowsheetRect.prototype, {
		_createPoint:function(entity,id,index,x,y){
			var circle = entity._svg.circle(this.g,x,y,5,{class: 'control_point'});
			var self = this;
			//鼠标按下事件
			$(circle).mousedown(function(event){
				if(!entity._event){
					var inLine = $(this).data('input');
					if(inLine){
						entity._event = new FlowsheetEvent('link',inLine,event,{});
						entity._event.dx = inLine.options.endX - event.clientX;
						entity._event.dy = inLine.options.endY - event.clientY;
						entity.options.unlinkCallback.apply(entity,[entity._event]);
						inLine.options.toId = null;
						inLine.options.toIndex = null;
						$(this).data('input',null);
					}else{
						var outLine = $(this).data('output');	
						if(!outLine){
							outLine = new FlowsheetLine(entity,{
								fromId:id,
								fromIndex:index,
								startX:self.options.x+x,
								startY:self.options.y+y,
								endX:self.options.x+x,
								endY:self.options.y+y
							});
							entity._event = new FlowsheetEvent('link',outLine,event,{});
							entity._event.dx = outLine.options.endX - event.clientX;
							entity._event.dy = outLine.options.endY - event.clientY;
						}
						$(this).data('output',outLine);
					}
					event.stopPropagation();
				}
			});
			//鼠标弹起事件
			$(circle).mouseup(function(event){
				if(entity._event){
					if(entity._event.name == 'link'){
						entity._event.object.options.toId = id;
						entity._event.object.options.toIndex = index;
						entity._event.object.stopMove('end',event.clientX,event.clientY,entity._event.dx,entity._event.dy);
						$(this).data('input',entity._event.object);
						entity.options.linkCallback.apply(entity,[entity._event]);
						entity._event = null;
						event.stopPropagation();
					}
				}
			});
			return circle;
		},
		getPoint:function(i){
			return this['point'+i];
		},
		getPointXY:function(i){
			if(i==1){
				return {
					x:this.options.x,
					y:this.options.y + this.options.height/2
				}
			}else if(i==2){
				return {
					x:this.options.x + this.options.width,
					y:this.options.y + this.options.height/2
				}
			}else if(i==3){
				return {
					x:this.options.x + this.options.width/2,
					y:this.options.y
				}
			}else if(i==4){
				return {
					x:this.options.x + this.options.width/2,
					y:this.options.y + this.options.height
				}
			}
			return {x:0,y:0}
		},
		moveTo:function(mouseX,mouseY,dx,dy){
			var x = mouseX + dx,y = mouseY + dy;
			$(this.g).attr('transform','translate('+x+','+y+')');
			var self = this;
			$(this.g).find('.control_point').each(function(i,v){
				var inLine = $(v).data('input');	
				if(inLine){inLine.moveTo('end',x,y,inLine.options.endX-self.options.x,inLine.options.endY-self.options.y);}
				var outLine = $(v).data('output');
				if(outLine){outLine.moveTo('start',x,y,outLine.options.startX-self.options.x,outLine.options.startY-self.options.y);}
			});
		},
		stopMove:function(mouseX,mouseY,dx,dy){
			var x = mouseX + dx,y = mouseY + dy;
			var self = this;
			$(this.g).find('.control_point').each(function(i,v){
				var inLine = $(v).data('input');	
				if(inLine){inLine.stopMove('end',x,y,inLine.options.endX-self.options.x,inLine.options.endY-self.options.y);}
				var outLine = $(v).data('output');
				if(outLine){outLine.stopMove('start',x,y,outLine.options.startX-self.options.x,outLine.options.startY-self.options.y);}
			});
			this.options.x = x;
			this.options.y = y;
		}
	});
	/*
		{
			fromId:'',
			fromIndex:0,
			toId:'',
			toIndex:0,
			startX:0,
			startY:0,
			endX:0,
			endY:0
		}
    */	
	function FlowsheetLine(entity,options){
		this.options = $.extend({},options);
		//创建SVG元素
		this.arrow = this._createArrow(entity,this.options.endX,this.options.endY);
		this.line = entity._svg.line(entity._lineGroup,this.options.startX,this.options.startY,this.options.endX,this.options.endY,{stroke:'#000','stroke-width':3});
	}
	
	$.extend(FlowsheetLine.prototype, {
		/*
			创建线的指向箭头
		*/
		_createArrow:function(entity,x,y){
			var g = entity._svg.group(entity._lineGroup,{transform:'translate('+x+','+y+')'});
			entity._svg.circle(g,0, 0, 5);
			var self = this;
			//鼠标按下事件
			$(g).mousedown(function(event){
				entity._event = new FlowsheetEvent('link',self,event,{});
				entity._event.dx = self.options.endX - event.clientX;
				entity._event.dy = self.options.endY - event.clientY;
			})
			return g;
		},
		moveTo:function(type,mouseX,mouseY,dx,dy){
			var x = mouseX + dx,y = mouseY + dy;
			if(type === 'start'){
				$(this.line).animate({svgX1:x,svgY1:y},0);
			}else if(type === 'end'){
				$(this.arrow).attr('transform','translate('+x+','+y+')');
				$(this.line).animate({svgX2:x,svgY2:y},0);
			}
		},
		stopMove:function(type,mouseX,mouseY,dx,dy){
			var x = mouseX + dx,y = mouseY + dy;
			if(type == 'start'){
				this.options.startX = x;
				this.options.startY = y;
			}else if(type == 'end'){
				this.options.endX = x;
				this.options.endY = y;
			}
		}
	});
	
	var Flowsheet = function(element,options){
		this.element = element;
		this.options = $.extend({
			onLoad:function(){},
			createRectCallback:function(event){},
			rectStopMoveCallback:function(event){},
			linkCallback:function(event){},
			unlinkCallback:function(event){},
			dblclick:function(event){}
		},options);
		
		this.nodes = {}; //节点信息
		
		var self = this;
		$(this.element).svg({
			onLoad:function(svg){
				$(this).mouseup(function(event){
					if(self._event){
						if(self._event.name === 'createRect'){
							//滑动块？？
							self._event.options.x = (event.clientX + $('body').scrollLeft() + self._event.dx)-40;
							self._event.options.y = (event.clientY + $('body').scrollTop() + self._event.dy)-25;
							self.options.createRectCallback.apply(self,[self._event]);
						}else if(self._event.name === 'move'){
							self._event.object.stopMove(event.clientX,event.clientY,self._event.dx,self._event.dy);
							self.options.rectStopMoveCallback.apply(self,[self._event]);
						}else if(self._event.name === 'link'){
							self._event.object.stopMove('end',event.clientX,event.clientY,self._event.dx,self._event.dy);
						}
						self._event = null;
					}
				})
				
				$(this).mousemove(function(event){
					if(self._event){
						if(self._event.name === 'move'){
							self._event.object.moveTo(event.clientX,event.clientY,self._event.dx,self._event.dy);
						}else if(self._event.name === 'link'){
							self._event.object.moveTo('end',event.clientX,event.clientY,self._event.dx,self._event.dy);
						}
					}
				})
				
				//创建线组
				self._lineGroup = svg.group();
				self.options.onLoad.apply(self);
			}
		});
		
		this._svg = $(this.element).svg('get');
	}
	
	Flowsheet.prototype = {
		/*
			{
				nodes:[{
					id:'',
					name:'',
					x:0,
					y:0,
					width:0,
					height:0
				},{...}],
				lines:[{
					fromId:'',
					fromIndex:0,
					toId:'',
					toIndex:0,
					startX:0,
					startY:0,
					endX:0,
					endY:0
				},{...}]
			}
		*/
		loadData:function(data){
			var self = this;
			$.each(data.nodes || [],function(i,obj){
				self.createRect(obj);
			});
			$.each(data.lines || [],function(i,obj){
				//获取开始点
				var startNode = self.nodes[obj.fromId];
				if(startNode){
					var start = startNode.getPoint(obj.fromIndex);
					var startXY = startNode.getPointXY(obj.fromIndex);
					obj.startX = startXY.x;
					obj.startY = startXY.y;
					var endNode = self.nodes[obj.toId];
					if(endNode){
						var endXY = endNode .getPointXY(obj.toIndex);
						obj.endX = endXY.x;
						obj.endY = endXY.y;
						var line = new FlowsheetLine(self,obj);
						$(endNode.getPoint(obj.toIndex)).data('input',line);
						$(start).data('output',line);
					}else{
						var line = new FlowsheetLine(self,obj);
						$(start).data('output',line);
					}
				}
			});
		},
		createRect:function(options){
			if(!options.width){options.width = 80;}
			if(!options.height){options.height = 50;}
			this.nodes[options.id] = new FlowsheetRect(this,options);
		},
		updateRect:function(options){
			var node = this.nodes[options.id];
			if(node){
				node.options.name = options.name;
				$(node.text).html(options.name);
			}
		},
		event:function(eventName,options){	
			this._event = new FlowsheetEvent(eventName,null,null,options);
			var offset = $(this.element).offset();
			this._event.dx = -offset.left;
			this._event.dy = -offset.top;
		}
	}
	
	$.fn.flowsheet = function(){
		var args = Array.prototype.slice.call(arguments, 0);
		var value = undefined;
		this.each(function () {
			var $this = $(this);
			if (args.length === 0 || typeof(args[0]) === "object") {
				opts = args.length === 0 ? {} : $.extend({}, args[0]);
				$this.data(KEY,new Flowsheet(this,opts)); //创建控件
			}else if (typeof(args[0]) === "string"){
				var entity = $this.data(KEY);
				if(entity === undefined){return;}
				value = entity[args[0]].apply(entity, args.slice(1));
			}else{
				 throw 'Invalid arguments to '+KEY+' plugin: ' + args;
			}
	    });
	    return (value === undefined) ? this : value;
	};
	
	$.fn.flowsheet.Constructor = Flowsheet;
	
})(window.jQuery);